-
-
Notifications
You must be signed in to change notification settings - Fork 115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(compiler)!: Custom Grain object files #2104
base: main
Are you sure you want to change the base?
Conversation
@@ -377,6 +377,6 @@ describe("basic functionality", ({test, testSkip}) => { | |||
~config_fn=smallestFileConfig, | |||
"smallest_grain_program", | |||
"", | |||
4769, | |||
6424, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did this go up?
Is it because of names changing and debug info?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant to leave a comment about this; thanks for pointing it out. The old linker had a concept of hard/soft dependencies. If a file was a dependency but no values/functions from that module were actually uses (just types or an unused import), then the linker would compile in type information but not link in the actual files.
At first thought this seems like good behavior, but if this is done, side effects from importing those modules don't happen, which is bad. For example, a normal Grain program that doesn't use anything in Pervasives
doesn't link in Pervasives
, which means the setupExceptions
side effects don't happen, and throwing exceptions in those programs prints GrainError
instead of the actual error. In practice, users don't run into this because most programs use something from Pervasives.
This new linker links in all dependencies, which is more correct. As I mentioned, in practice this doesn't make a real difference for most users. Side note: the major reason the original implementation did this was because the compiler wasn't great at removing unused code from the resulting binary and this resulted in large module sizes. The compiler has gotten much better and this isn't really an issue anymore.
I also discovered a few more configurations producing smaller programs while working on this, as small as 25 bytes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah okay then this probably closes #1903 then.
92e6423
to
89fcb11
Compare
193e5ec
to
6ac38da
Compare
@alex-snezhko This should be ready for you to look at again. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did not see any obvious problems, LGTM!
compiler/src/codegen/compcore.re
Outdated
Function.set_start(wasm_mod, start); | ||
} else { | ||
ignore @@ | ||
Export.add_function_export(wasm_mod, "_start", Comp_utils.grain_start); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: inconsistent use of grain_start
constant and "_start" literal (a few other times in the lines above)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly looks great to me, I love the new implementation but I have a few questions.
We should probably also update the contributer docs in this pr so they do not get too far out of date.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, can we also open an issue to update the linking section in the contributer docs, we should probably include the binary format there, and some stuff from the pr description.
d6920a8
to
e4632f3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great to me, I had one tiny question and it looks like some of the tests are failing currently.
I love that we are using an exceptionMod
flag it seems a lot less fragile then file paths.
Before we get this merged could we update the static linking contributor docs I think the pr description covers a lot of the content we would want.
compiler/src/compile.re
Outdated
@@ -149,6 +149,7 @@ let next_state = (~is_root_file=false, {cstate_desc, cstate_filename} as cs) => | |||
Grain_utils.Config.apply_attribute_flags( | |||
~no_pervasives=has_attr("noPervasives"), | |||
~runtime_mode=has_attr("runtimeMode"), | |||
~no_exception_mod=has_attr("exceptionMod"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about "noExceptionMod" to keep with the pattern of "noPervasives"? I assume you did this because currently this attribute would only be used on the exception module so it is taken to mean "this is the exception module", but "noExceptionMod" more accurately reflects what the flag is actually doing I feel.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had thought of noExceptions
but I thought that was too ambiguous, but I've come around on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
@spotandjake I updated the contributor docs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great oscar, im excited to get this into main I had one tiny NIT left but otherwise lgtm.
@@ -1,5 +1,5 @@ | |||
@noPervasives | |||
@exceptionMod | |||
@noExceptions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One tiny NIT, do we just want to add a comment here something like, // Exceptions cannot be thrown from the exception module or we would have a circular dependency.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
I really like the new approach, and the code read fine - I'll not spot any bugs though but looking forward to this being the new way of generating code.
72784ac
to
eef00bd
Compare
Overview
This PR replaces Grain's intermediate
.gr.wasm
files with Grain object files. This is for a variety of reasons, including:Technical details
Grain object files use the
.gro
extension. As no wasm files are specific to Grain, the default output filename from the compiler uses the.wasm
extension rather than.gr.wasm
.Object files follow this layout:
We use OCaml's
Marshal
module as our binary format (and for Whole Grain, we can use ourMarshal
module). js_of_ocaml can't marshal floats into a format that can safely be read back by native code. I wanted object files to be the same between native and js, so we store floats asint64
s in the mashtree to guarantee consistent behavior.Reviewing this PR
The code delta for this PR is fairly small, but snapshot tests are now sexprs of mashtrees. As such, we have all new snapshots. I'd recommend clicking the first commit to review the code diff, or using the GitHub UI to hide changes to snapshots.
Closes #622
Closes #842
Closes #1754
Closes #1903
Closes #1997